package com.melody.rest.aspect;


import cn.hutool.core.bean.BeanUtil;
import com.melody.rest.annotion.AuthCheck;
import com.melody.rest.domain.RestSysUser;
import com.melody.rest.exception.AuthException;
import com.melody.rest.model.ResCode;
import com.melody.rest.model.ResJson;
import com.melody.rest.model.ResultCode;
import com.melody.rest.model.ResultJson;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;


import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.util.Map;

@Aspect
@Component
public class AuthAspect {

    @Value("${token.header}")
    //@Value("authorization")
    private String header;

    @Autowired
    private HttpServletRequest request;

    @Resource
    private RedisTemplate redisTemplate;

    @Pointcut("@annotation(com.melody.rest.annotion.AuthCheck)")
    public void authPointCut(){

    }

    @Around("authPointCut()")
    public Object authCheck(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        try{
            // 判断 TOKEN
            String token = request.getHeader(header);
            Map<String, Object> userMap=redisTemplate.opsForHash().entries(token);
            RestSysUser restSysUser = BeanUtil.fillBeanWithMap(userMap, new RestSysUser(), false);
            if(restSysUser.getUsername() == null || restSysUser.getUsername().equals("")){
                throw new AuthException(ResCode.TOKEN_NOT_EXIST);
            } else {
                if(restSysUser.getResources()==null){
                    throw new AuthException(ResCode.BANED_REQUEST);
                }
                //从切面织入点处通过反射机制获取织入点处的方法
                MethodSignature signature = (MethodSignature) proceedingJoinPoint.getSignature();
                //获取切入点所在的方法
                Method method = signature.getMethod();
                AuthCheck ac = method.getAnnotation(AuthCheck.class);
                boolean flag = false;
                if(ac != null) {
                    String auth = ac.value();
                    flag = restSysUser.getResources().stream().anyMatch(str -> str.equals(auth));
                    // way2:数据库中存放权限字段，根据注解的value确定请求所需权限判断是否有权限进行访问
                }
                if(!flag) {
                    //throw new AuthException(ResCode.BANED_REQUEST);
                    return ResultJson.failure(ResultCode.FORBIDDEN);
                }
            }
        } catch(AuthException e) {
            System.err.println(e.getResCode().getCode() + ":" + e.getResCode().getMsg());
            return ResJson.no(e.getResCode());
        }
        Object res = proceedingJoinPoint.proceed();
        return res;
    }

}
